1-4 禰貌

表單(Forms)是 HTML 的一個重要標籤。一般的 HTML 標籤,只是為了用來呈現網頁的資訊,以便使用者在客戶端瀏覽。表單不只是有呈現資訊的功能,更重要的是,它包含了數種表單元素(Form Elements),可以讓使用者進行資料填寫或選取的功能,並將使用者所填寫的資料送到伺服器端,進行必要的處理。因此我們可以說,表單就是客戶端和伺服器進行資訊溝通的第一個門面。

表單將使用者輸入的資料送到伺服器後,伺服器端必須有相對的程式來對資料進行處理(例如送入資料庫或進行統計分析)。由於本章仍屬於 HTML 範疇,因此我們在本節只會介紹表單在 HTML 中的原始碼,及其在網頁中所呈現的外觀,以便讓讀者瞭解如何使用表單元素來設計基本的動態網頁。有關表單的詳細介紹,可見本書有關於「表單」的章節。此外,有關在伺服器端處理表單資料的程式,我們會在本書第二篇「用於伺服器端的 JavaScript」的相關章節進行說明。

所謂「百聞不如一見」,讓我們先看看一個表單的簡單範例:

Example(form01.htm):

上述範例的完整原始檔案如下:

原始檔(form01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>基本表單範例</h2>
<hr>

<form action="mailto:test@cs.nthu.edu.tw" encType=text/plain method=post>
	<p>名字:<input name="myname" size=10 maxlength=20 value="蕭亞軒">
	<p>密碼:<input name="passwd" type=password size=8 maxlength=8 value=xyz>
	<p>性別(單選):<input name="sex" type=radio value="男">男
		<input name="sex" type=radio value="女" checked>女
	<p>嗜好(複選):
		<input name="f1" type=checkbox value="book">閱讀
		<input name="f2" type=checkbox value="sport" checked>運動
		<input name="f3" type=checkbox value="music" checked>音樂
		<input name="f4" type=checkbox value="sleep">睡覺
		<input name="f5" type=checkbox value="talk">聊天<P>
	<p><input type="submit"> <input type="reset">
</form>

<hr>
</body>
</html>

由上述的範例可看出,表單是由 form 標籤所形成,可包含數個選項,action 代表表單傳送的目的位址(也就是處理表單資訊的伺服器程式),method 則代表表單資訊的傳送方法。在上例中,action 是設定成一個電子郵件帳號,因此當使用這按下「送出表單」時,所有在表單輸入的資料,會被送到此電子郵件帳號 test@cs.nthu.edu.tw,所收到電郵的主旨是「從 Microsoft Internet Explorer 公佈表格。」,電郵的的內容是:

myname=蕭亞軒
passwd=xyz
sex=女
f2=sport
f3=music
(上例中的郵件帳號 test@cs.nthu.edu.tw 是亂寫的,因此如果你直接將表單送出,最後可能會遭到退件。)有關於 method 選項,在此不細談,讀者可先參考有關 ASP 或 CGI 的章節。

在表單內部,還有許多表單元素(Form Elements),或稱表單控制項(Form Controls),以便讓使用者輸入資料。以上例而言,這些表單元素的標籤都是 input,並根據 type 的不同,而有不同的功能。這些表單元素有些各式各項的屬性(Attributes)以及其相關的性質(Properties),我們可以使用 JavaScript 來改變這些性質,就可以建立較為有趣且有用的互動式網頁。

我們先來看一個單列文字輸入的範例,在此範例中,你只要按下「送到狀態列」,JavaScript 就會把你填入的文字送到狀態列:

Example(formText2status01.htm):

上述範例的原始檔如下:

原始檔(formText2status01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>將文字欄位送到狀態列</h2>
<hr>

<form name=theForm>
	<input type=text name="theString" value="送到狀態列的預設訊息">
	<input type=button value="送到狀態列" onClick="window.status=document.theForm.theString.value">
</form>

</body>
</html>

在上述範例中,當我們按下「送到狀態列」的按鈕時,瀏覽器會去執行定義於 onClick 的字串,此字串是一串 JavaScript 的敘述,其功能可分成兩段來說明:

  1. 抓出文字欄位內的文字:其中 document 是此文件,theForm 是我們定義的表單名稱,theString 也是我們定義的文字欄位名稱,而 value 則是文字欄位內建的一個性質名稱,因此 document.theForm.theString.value 就是指文字欄位中的文字。
  2. 將此文字送到狀態列:直接設定 window.status 即可。

Hint
在嘗試上述範例時,你必須先顯示瀏覽器的狀態列,可經由「檢視/狀態列」來開啟或關閉瀏覽器的狀態列。

網頁內如果有多個表單,我們可以分別使用「document.forms[n]」來表示,其中 n = 0, 1, 2 等等。但一般來說,一個網頁通常只有一個表單,因此若不定義此表單的名稱,我們也可以直接使用 document.forms[0] 來代表此表單。

事實上,在上述的範例中,我們可以使用文字輸入欄位的另一個屬性 onChange,來判斷文字欄位內的文字是否遭到修改,若有,才將此段文字送到狀態列,請見下列範例:

Example(formText2status02.htm):

上述範例的原始檔如下:

原始檔(formText2status02.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>將文字欄位送到狀態列:使用 onChange 事件</h2>
<hr>

<form>
	<input type=text value="送到狀態列的預設訊息" onChange="window.status=this.value">
</form>

</body>
</html>

在上述範例中,只要我們改變文字欄位中的預設文字,同時將焦點(Focus)移出此文字欄位時(只要使用滑鼠點選一下網頁其它地方),定義於 onChange 的 JavaScript 程式碼即會被呼叫來更新瀏覽器的狀態列。和前一個範例比較,我們可以發現此範例更為簡潔:

  1. 文字轉換的動作定義於文字欄位的 onChange 屬性,所以可以省卻按鈕的使用。(但是 onChange 事件只有在滑鼠的焦點由文字欄位消失時,才會起作用。)
  2. 我們使用 this 來代表「目前的控制項」,因此不必定義文字欄位和表單的名稱,網頁更為簡潔。

Hint
在上述範例中,如果希望在文字欄位填入文字時,狀態列能夠立即改變,可將 onChange 改成 onKeyUp 即可。請同學們試試看!

使用 this 來代表「目前的控制項」,是一個常被用到的技巧。另外,我們也可以使用 this.form 來代表「目前的控制項所在的表單」,因此可以省略了定義表單的步驟,例如:

Example(formTextMasterSlave01.htm):

上述範例的原始檔如下:

原始檔(formTextMasterSlave01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>傳送兩個文字欄位的訊息:使用 this.form</h2>
<hr>

<form>
	<input type=text name=text1 value="送到右邊的預設訊息">
	<input type=button value="=====>" onClick="this.form.text2.value=this.form.text1.value">
	<input type=text name=text2>
</form>

</body>
</html>

在上述範例中,當我們點選「====>」的按鈕,就會將左邊的文字傳到右邊,其中 this.form 就是代表按鈕所在的表單。

Hint
一般而言,以「a.b」的方式來指到一個物件,例如 form1.input1 等,是由大(表單)到小(控制項)的方式,但唯一的例外,就是 this.form,這是由小(控制項)到大(表單)的方式。

我們也可以使用類似的方式來傳送核記方塊的資料,例如:

Example(formCheckboxMasterSlave01.htm):

上述範例的原始檔如下:

原始檔(formCheckboxMasterSlave01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>傳送兩個核記欄位的訊息:使用相對路徑 this.form</h2>
<hr>

<form>
	<input type=checkbox name=box1 checked>
	<input type=button value="=====>" onClick="this.form.box2.checked=this.form.box1.checked">
	<input type=checkbox name=box2>
</form>

</body>
</html>

在上述範例中,每次你修改第一個核記方塊並移除焦點時,我們就用警告視窗來顯示其性質 checked 的值,true 代表勾選,false 代表不勾選。接著我們可以按下「====>」的按鈕,即可將相關的勾選資訊從左邊傳到右邊。

如果不是用 this.form 來達到上述效果,程式碼就會比較繁雜,如下所示:

原始檔(formCheckboxMasterSlave02.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>傳送兩個核記欄位的訊息:使用絕對路徑</h2>
<hr>

<form name=myForm>
	<input type=checkbox name=box1 checked>
	<input type=button value="=====>" onClick="document.myForm.box2.checked=document.myForm.box1.checked">
	<input type=checkbox name=box2>
</form>

</body>
</html>

由上述範例可以看出,使用 this.form 就類似於使用相對路徑,有時候會比使用絕對路徑來的方便與簡潔。

另一種方式,則是使用 id 標籤於表單元件,然後使用 document.getElementById(id) 來取得此元件,範例如下:

Example(formCheckboxMasterSlave03.htm):

上述範例的原始檔如下:

原始檔(formCheckboxMasterSlave03.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>傳送兩個核記欄位的訊息:使用 id</h2>
<hr>

<form name=myForm>
	<input type=checkbox id=box1 checked>
	<input type=button value="=====>" onClick="document.getElementById('box2').checked=document.getElementById('box1').checked">
	<input type=checkbox id=box2>
</form>

</body>
</html>

在此範例中,無論此元件的位置為何,我們都可以直接使用 document.getElementById(id) 來取得此元件,非常方便。

除了收音機按鈕和核記方塊之外,我們也可以使用下拉式選單(Pull-down Menus)來讓使用者進行選項的勾選,所用的標籤是 select。若要進行單選,範例如下:

Example(formSelectSingle01.htm):

上述範例的原始檔如下:

原始檔(formSelectSingle01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>下拉選單:單選</h2>
<hr>

請選一個你最喜歡的課程:
<form>
<select name=courseList size=4 onChange="alert('你選的課程是「'+this.options[this.selectedIndex].text+'」')">
	<option> 1. Linear Algebra
	<option> 2. C Programming Language
	<option> 3. Engineering Mathematics
	<option> 4. Numerical Methods
	<option> 5. Introduction to Artificial Intelligence
	<option selected> 6. Web Programming
	<option> 7. Artificial Neural Networks
	<option> 8. Fuzzy Sets Theory and Applications
	<option> 9. Audio Signal Processing and Recognition
	<option> 10. Special Topics on MATLAB
</select>
</form>

<hr>
</body>
</html>

若要進行複選,所用的標籤還是 select,只是需要加入 multiple 的屬性,範例如下:

Example(formSelectMultiple01.htm):

上述範例的原始檔如下:

原始檔(formSelectMultiple01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>下拉選單:多選</h2>
<hr>

<script>
function listSummary(form) {
	var result = "";
	for (var i=0; i<form.courseList.length; i++)
		if (form.courseList.options[i].selected)
			result = result + form.courseList.options[i].text + "\n"; 
	alert("你最喜歡的幾門課是:\n" + result);
}
</script>

請選擇你最喜歡的幾門課(可用 Ctrl 或 Shift 鍵來進行多選):
<form>
<select name=courseList size=4 multiple onChange="listSummary(this.form)">
	<option> 1. Linear Algebra
	<option> 2. C Programming Language
	<option> 3. Engineering Mathematics
	<option selected> 4. Numerical Methods
	<option> 5. Introduction to Artificial Intelligence
	<option selected> 6. Web Programming
	<option> 7. Artificial Neural Networks
	<option> 8. Fuzzy Sets Theory and Applications
	<option> 9. Audio Signal Processing and Recognition
	<option> 10. Special Topics on MATLAB
</select>
</form>

<hr>
</body>
</html>

在上述範例中的 listSummary() 函式中,我們在 result 變數之前加上了 var,這代表 result 是一個局部變數(Local Variable),換句話說,這個變數只有在 listSummary() 函式中存在,也只有在這個函式中,我們能夠存取這個變數,一旦不在此函式內,此變數就完全不存在。一般而言,如果沒有在函式內的變數加上 var 的宣告,那麼這個變數就預設成全域變數(Global Variable),你可以在函式以外的任何地方存取此變數。

Hint
一般我們建議在函式內的變數都盡量設定成局部變數,以減少函式呼叫後可能產生的非預期副作用。

若要輸入大量文字資料,就必須使用 textarea 標籤,範例如下:

Example(formTextarea01.htm):

上述範例的原始檔如下:

原始檔(formTextarea01.htm):(灰色區域按兩下即可拷貝)
<html>
<head>
<meta HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=big5">
</head>

<body>
<h2 align=center>多列文字欄位:textarea</h2>
<hr>

請修改下列文字後,在點選滑鼠於表單之外。
<form>
<textarea name=courseList cols=80 rows=10 onChange="alert('更改後的文字:\n'+this.value)">
This is the text within the textarea tag.
這是位於 textarea 標籤內的文字。
</textarea>
</form>

<hr>
</body>
</html>

最後還有兩個常用的控制項,就是 submit 和 reset,其功能如下:

這些相關細節,我們還會在後續章節詳細說明。
JavaScript 程式設計與應用:用於網頁用戶端